package app.controllers;

import app.Const;
import app.constant.OrderConstant;
import app.constant.ProductConstant;
import app.constant.TransferConstant;
import app.dtos.PayDto;
import app.kit.TypeKit;
import app.models.order.Order;
import app.models.order.TradeMoney;
import app.models.product.Product;
import app.models.transfer.TransferProduct;
import app.services.TradeService;
import app.services.TransferService;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.hundsun.epay.pay.CodeUtil;
import com.hundsun.epay.pay.certkey.CertUtil;
import com.jfinal.aop.Before;
import com.jfinal.ext.interceptor.POST;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import goja.Logger;
import goja.StringPool;
import goja.mvc.Controller;
import goja.tuples.Pair;

import java.sql.SQLException;
import java.util.Map;

import static app.Const.FIELD_PRODUCT;
import static app.Const.FIELD_STATUS;
import static app.constant.OrderConstant.NEW;
import static app.constant.OrderConstant.TOBEPAY;
import static app.constant.OrderConstant.TRADE_SUCCESS;
import static bank.BankConstant.BP_PARTNER_BUYER_ID;
import static bank.BankConstant.BP_PARTNER_ID;
import static bank.BankConstant.RSK_RESBIZDATE;
import static bank.BankConstant.SIGN;
import static bank.BankConstant.SIGNTYPE;

/**
 * <p>
 * The url pay Controller.
 * 银行支付回调借口
 * </p>
 *
 * @author sagyf yang
 * @version 1.0
 * @since JDK 1.6
 */
public class PayController extends Controller {

    /**
     * 成功
     */
    public static final int SUCCESS      = 1;
    /**
     * 状态错误
     */
    public static final int STATUS_ERROR = 0;
    /**
     * 失败
     */
    public static final int FAIL         = 2;

    /**
     * The index route.
     * the url /pay
     * the view in index.ftl
     */
    public void index() {
        renderError(404);
    }

    /**
     * 更改订单状态
     */
    @Before(POST.class)
    public void order() {
        long orderId = getParaToLong(0, 0L);
        if (orderId > 0) {
            Order order = Order.dao.findById(orderId);
            if (TypeKit.getStatus(order) == NEW) {
                order.set(Const.FIELD_STATUS, TOBEPAY);
                if (order.update()) {
                    renderAjaxSuccess();
                    return;
                }
            }
        }
        renderAjaxFailure();
    }


    /**
     * 支付同步通知
     */
    @Before(POST.class)
    public void tip() {
        String partnerId = getPara(BP_PARTNER_ID);
        String partnerBuyerId = getPara(BP_PARTNER_BUYER_ID);
        /*
        订单状态：
            0-待支付，1-退款处理中，2-处理中，3-交易成功，4-交易关闭，
            5-删除，6-已退款，7-交易失败，8-交易完成
         */
        String orderStatus = getPara("orderStatus");

        /* 交易总金额，精确到小数点后面两位 */
        String totalAmount = getPara("totalAmount");
        String currency = getPara("currency");
        String fee = getPara("fee");
        String outerOrderNo = getPara("outerOrderNo");
        if (Strings.isNullOrEmpty(outerOrderNo)) {
            setAttr(FIELD_STATUS, 1);
            return;
        }
        String innerOrderNo = getPara("innerOrderNo");
        String respBizDate = getPara(RSK_RESBIZDATE);
        String sign = getPara(SIGN);
        String signType = getPara(SIGNTYPE);

        String field1 = getPara("field1");
        String field2 = getPara("field2");
        String field3 = getPara("field3");
        String respCode = getPara("respCode");
        String respMsg = getPara("respMsg");




        try {
            partnerId = CodeUtil.deCode(partnerId, StringPool.UTF_8);
            partnerBuyerId = CodeUtil.deCode(partnerBuyerId, StringPool.UTF_8);
            orderStatus = CodeUtil.deCode(orderStatus, StringPool.UTF_8);
            totalAmount = CodeUtil.deCode(totalAmount, StringPool.UTF_8);
            currency = CodeUtil.deCode(currency, StringPool.UTF_8);
            fee = CodeUtil.deCode(fee, StringPool.UTF_8);
            outerOrderNo = CodeUtil.deCode(outerOrderNo, StringPool.UTF_8);
            innerOrderNo = CodeUtil.deCode(innerOrderNo, StringPool.UTF_8);
            respBizDate = CodeUtil.deCode(respBizDate, StringPool.UTF_8);
            respMsg = CodeUtil.deCode(respMsg, StringPool.UTF_8);
        } catch (Exception e) {
            Logger.error("回调请求参数解析错误,", e);
        }
        Logger.info("同步回调验签初始respMsg=:{}", respMsg);
        System.out.println("同步回调验签初始respMsg=:" + respMsg);

        Map<String, String> paramMap = Maps.newHashMap();
        paramMap.put("partnerId", partnerId);
        paramMap.put("partnerBuyerId", partnerBuyerId);
        paramMap.put("orderStatus", orderStatus);
        paramMap.put("totalAmount", totalAmount);
        paramMap.put("currency", currency);
        paramMap.put("fee", fee);
        paramMap.put("outerOrderNo", outerOrderNo);
        paramMap.put("innerOrderNo", innerOrderNo);
        paramMap.put("field1", field1);
        paramMap.put("field2", field2);
        paramMap.put("field3", field3);
        paramMap.put("respBizDate", respBizDate);
        paramMap.put("respCode", respCode);
        paramMap.put("respMsg", respMsg);
        paramMap.put("signType", signType);
        paramMap.put("sign", sign);

        boolean isMerchantVerify;
        String signContent;
        try {
            signContent = CodeUtil.getJoinStrByParamMap(paramMap);

            isMerchantVerify = CertUtil.verifyKeyPairSign4Merchant(signContent);
            Logger.info("同步回调验签结果:{}", isMerchantVerify ? "成功" : "失败");
        } catch (Exception e) {
            e.printStackTrace();
        }

        PayDto payDto = PayDto.createPayReturn(orderStatus, totalAmount, fee, outerOrderNo, innerOrderNo, respBizDate);

        final Optional<Pair<Order, Integer>> order_opt = execOrder(payDto);
        if (order_opt.isPresent()) {
            Order order = order_opt.get().getValue0();
            setAttr("order", order);
            setAttr(FIELD_STATUS, order_opt.get().getValue1());
        } else {
            setAttr(FIELD_STATUS, 1);
        }

    }

    /**
     * 支付异步通知
     */
    public void asyn() {

        String partnerId = getPara(BP_PARTNER_ID);
        String partnerBuyerId = getPara(BP_PARTNER_BUYER_ID);
        /*
        订单状态：
            0-待支付，1-退款处理中，2-处理中，3-交易成功，4-交易关闭，
            5-删除，6-已退款，7-交易失败，8-交易完成
         */
        String orderStatus = getPara("orderStatus", StringPool.ZERO);
        /* 交易总金额，精确到小数点后面两位 */
        String totalAmount = getPara("totalAmount");
        String currency = getPara("currency");
        String fee = getPara("fee");
        String outerOrderNo = getPara("outerOrderNo");
        String innerOrderNo = getPara("innerOrderNo");
        String sign = getPara(SIGN);
        String signType = getPara(SIGNTYPE);
        try {
            partnerId = CodeUtil.deCode(partnerId, StringPool.UTF_8);
            partnerBuyerId = CodeUtil.deCode(partnerBuyerId, StringPool.UTF_8);
            orderStatus = CodeUtil.deCode(orderStatus, StringPool.UTF_8);
            totalAmount = CodeUtil.deCode(totalAmount, StringPool.UTF_8);
            currency = CodeUtil.deCode(currency, StringPool.UTF_8);
            fee = CodeUtil.deCode(fee, StringPool.UTF_8);
            outerOrderNo = CodeUtil.deCode(outerOrderNo, StringPool.UTF_8);
            innerOrderNo = CodeUtil.deCode(innerOrderNo, StringPool.UTF_8);
        } catch (Exception e) {
            Logger.error("回调请求参数解析错误,", e);
        }

        PayDto payDto = PayDto.createPayNotify(orderStatus, totalAmount, fee, outerOrderNo, innerOrderNo);

        final Optional<Pair<Order, Integer>> order_opt = execOrder(payDto);
        if (order_opt.isPresent()) {
            if (order_opt.get().getValue1() == SUCCESS) {
                renderAjaxSuccess();
            } else {
                renderError(302);
            }
        } else {
            renderError(302);
        }
    }


    /**
     * 执行订单
     *
     * @param payDto 支付信息
     * @return 处理结果
     */
    private Optional<Pair<Order, Integer>> execOrder(PayDto payDto) {
        final Order order = Order.dao.findByOrderNo(payDto.outerOrderNo);
        if (order == null) {
            return Optional.absent();
        }
        if (TypeKit.getStatus(order) == TRADE_SUCCESS) {
            return Optional.of(Pair.with(order, SUCCESS));
        }
        int exec_status = 0;
        // 3 表示订单支付成
        if (payDto.orderStatus == TRADE_SUCCESS) {
            // 交易成功
            // 产品ID
            final int productId = TypeKit.getInt(order, FIELD_PRODUCT);

            final int dbOrderStatus = TypeKit.getStatus(order);
            if (dbOrderStatus == TOBEPAY) {
                /*未处理的订单*/
                /* 转让产品 */
                final int transferProductId = TypeKit.getInt(order, "transfer_product");
                boolean exec_ok;
                if (transferProductId > 0) {
                    // 该订单为购买转让产品

                    // 转让产品信息
                    final TransferProduct transferProduct = TransferProduct.dao.findByAllInfo(transferProductId);
                    // 产品状态
                    if (TypeKit.getStatus(transferProduct) != TransferConstant.STATUE_TRADING) {
                        // 产品非交易，无法完成支付
                        Logger.error("转让产品非交易中，无法完成支付");
                        order.set(FIELD_STATUS, OrderConstant.TRADE_FAILURE);
                        final TradeMoney tradeMoney = TradeMoney.payFail(productId, payDto.totalAmount,
                                order.getStr("membercode"), TypeKit.getInt(order, "member"), order);
                        Db.tx(new IAtom() {
                            @Override
                            public boolean run() throws SQLException {
                                return tradeMoney.save() && order.update();
                            }
                        });
                        return Optional.of(Pair.with(order, STATUS_ERROR));
                    }
                    // 产品ID
                    exec_ok = TransferService.me.transfer(payDto, order, transferProduct);
                } else {
                    /* 产品 */
                    // 产品信息
                    final Product buy_product = Product.dao.findById(productId);
                    int status = TypeKit.getStatus(buy_product);
                    // 产品状态
                    if (status != ProductConstant.ONLINE) {
                        // 产品非上架，无法完成支付
                        order.set(FIELD_STATUS, OrderConstant.TRADE_FAILURE);
                        final TradeMoney tradeMoney = TradeMoney.payFail(productId, payDto.totalAmount,
                                order.getStr("membercode"), TypeKit.getInt(order, "member"), order);
                        Db.tx(new IAtom() {
                            @Override
                            public boolean run() throws SQLException {
                                return tradeMoney.save() && order.update();
                            }
                        });
                        return Optional.of(Pair.with(order, STATUS_ERROR));
                    }
                    exec_ok = TradeService.me.pay(payDto, order, buy_product);
                }
                exec_status = exec_ok ? SUCCESS : FAIL;
            }
        } else {
            // 交易失败
            order.set(FIELD_STATUS, OrderConstant.TRADE_FAILURE);
            order.update();
            exec_status = FAIL;
        }
        return Optional.of(Pair.with(order, exec_status));
    }


}